#pragma once
#include <unordered_map>
#include "Common.hpp"
#include "TcpServer.hpp"
#include "Socket.hpp"
#include "Util.hpp"
using namespace std;
const string blank = " ";
const string mark = "\r\n";
const string kv_mark = ": ";
const string webroot = "./wwwroot";
const string homepage = "index.html";
const string errofile = "404.html";
class HttpRequest
{
public:
    HttpRequest() : _is_interact(false) {}
    void DecodeRequestLine(string &out)
    {
        stringstream ss(out);
        ss >> _reqWay >> _uri >> _httpVer;
    }
    void Deserialize(string &req)
    {
        string out;
        // 获取请求行//解码头行
        Util::GetOneline(req, &out, mark);
        DecodeRequestLine(out);
        if (_uri == "/")
            _uri = webroot + _uri + homepage;
        else
            _uri = webroot + _uri;
        // 反序列化请求报头
        out.clear();
        Util::GetOneline(req, &out, mark);
        while (out != "")
        {
            int pos = out.find(kv_mark);
            if (pos == string::npos)
            {
                LOG(Level::WARING) << "decode kv fail";
                return;
            }
            _headpage[out.substr(0, pos)] = out.substr(pos + kv_mark.size());
            out.clear();
            Util::GetOneline(req, &out, mark);
        }
        // 空行
        _blankline = "\r\n";
        // 获取请求正文
        _text = req;
        //cout<<_uri<<endl;
        string tmp = "?";
        int pos = _uri.find(tmp);
        if (pos == string::npos)
        {
            return;
        }
        cout<<"is_interact"<<endl;
        _args = _uri.substr(pos + tmp.size());
        _uri = _uri.substr(0, pos);
        _is_interact = true;
    }
    string getUri() { return _uri; }
    bool getIsInteract() { return _is_interact; }
    string getArgs() { return _args; }

private:
    string _reqWay;
    string _uri;
    string _httpVer;

    unordered_map<string, string> _headpage;
    string _blankline;
    string _text;
    string _args;
    bool _is_interact;
    // 资源文件地址
    // string _filename;
};
class HttpResponse
{
public:
    string Serialize()
    {
        string target_str =
            _httpVer + blank + to_string(_statCode) + blank + _statCodeStr + mark;
        for (auto [k, v] : _headpage)
        {
            target_str += k + kv_mark + v + mark;
        }
        target_str += mark;
        target_str += _text;
        return target_str;
    }
    void SetCode(int code)
    {
        string ret;
        switch (code)
        {
        case 200:
            ret = "SUCCESS";
            break;
        case 404:
            ret = "Not Found";
            break;
        // 永久重定向
        case 301:
            ret = "Moved Permanently";
        // 临时重定向
        case 302:
            ret = "See Other";
        default:
            ret = "None";
        }
        _statCode = code;
        _statCodeStr = ret;
    }
    void SetHeader(const string &key, const string &value)
    {
        auto pos = _headpage.find(key);
        if (pos != _headpage.end())
            return;
        _headpage.insert(make_pair(key, value));
    }
    std::string Uri2Suffix(const std::string &targetfile)
    {
        int pos = targetfile.rfind(".");
        if (pos == string::npos)
        {
            return "text/html";
        }
        string str = targetfile.substr(pos);
        if (str == ".html" || str == ".htm")
            return "text/html";
        else if (str == ".txt")
            return ".txt";
        else if (str == ".png")
            return "image/png";
        else if (str == ".jpg" || str == ".jpeg")
            return "image/jpeg";
        else
            //......
            return "";
    }
    void setTargetFile(string uri)
    {
        _targetfile = uri;
    }
    void setText(string& str)
    {
        _text = str;
    }
    void MakeResponse()
    {
        _httpVer = "HTTP/1.1";
        bool f = Util::ReadFileContent(_targetfile, &_text);
        if(_targetfile == "./wwwroot/favicon.ico")
        {
            return;
        }
        // if (_targetfile == "https://www.baidu.com/")
        // {
        //     SetCode(301);
        //     SetHeader("Location", "https://www.csdn.net/");
        // }
        // if (!f)
        // {
        //     _text = "";
        //     _targetfile = webroot + "/" + errofile;
        //     Util::ReadFileContent(_targetfile, &_text);
        //     SetCode(404);
        // }
        if (!f)
        {
            SetCode(302);
            SetHeader("Location", "http://120.46.0.237:8080/404.html");
        }
        else
        {
            SetCode(200);
        }
        SetHeader("Content-Length", to_string(Util::FileSize(_targetfile)));
        SetHeader("Content-Type", Uri2Suffix(_targetfile));

        // Info
        for (auto [a, b] : _headpage)
        {
            cout << a << ":" << b << endl;
        }
    }

    // private:
    string _httpVer;
    int _statCode;
    string _statCodeStr;

    unordered_map<string, string> _headpage;
    string _blankline;
    string _text;
    //
    string _targetfile;
};

using http_func_t = function<void(HttpRequest &, HttpResponse &)>;

class Http
{
public:
    Http(uint16_t port)
        : tcpsv(make_unique<TcpServer>(port))
    {
    }
    void HttpHandlerRequest(shared_ptr<Socket> &sock, InetAddr &client)
    {
        string data;
        // 接收
        sock->Recv(&data);
        cout<<data<<endl;
        
        // 报文完整性检查
        //......
        // 解包
        HttpRequest req;
        req.Deserialize(data);
        // 业务处理（回调）
        HttpResponse rsp;
        if (req.getIsInteract())
        {
            if (_route.find(req.getUri()) == _route.end())
            {
                //
                LOG(Level::WARING)<<req.getUri()<<" Found Hander";
            }
            else
            {
                _route[req.getUri()](req, rsp); // 里面做MakeResponse的工作
                string data = rsp.Serialize();
                sock->Send(data);
            }
        }
        else
        {
            //......
            // 封包
            rsp.setTargetFile(req.getUri());
            rsp.MakeResponse();
            string send_str = rsp.Serialize();
            cout<<send_str<<endl;
            // 发送
            sock->Send(send_str);
        }
    }
    void Start()
    {
        tcpsv->Start([&](shared_ptr<Socket> &sock, InetAddr &client)
                     { HttpHandlerRequest(sock, client); });
    }
    void RegisterService(const std::string name, http_func_t h)
    {
        string key = webroot + name;
        cout<<"key:"<<key<<endl;
        auto it = _route.find(key);
        if (it == _route.end())
        {
            cout<<"OK"<<endl;
            _route[key] = h;
        }
    }

private:
    unique_ptr<TcpServer> tcpsv;
    unordered_map<string, http_func_t> _route;
};
